package com.albert.funny;


import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;

import com.albert.funny.GPSHandler.GPSHandlerListener;
import com.telenav.localproxy.request.GpsEncryptRequest;

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Looper;


public class CurrentLocationManager implements GPSHandlerListener
{
    public static final int FLAG_NEW_LOCATION_ARRIVAL = 0;
    public static final int FLAG_LOCATION_DEVICE_OFF = 1;
    public static final int FLAG_LOCATION_NO_LOCATION = 2;
    public static final int FLAG_LOCATION_REQUIRING = 3;
   
//    public static final int FLAG_LOCATION_PROVIDER_CHANGE = 4;
    
 
    public static final int LOCATION_NOTIFICATION_DURATION = 1000;
    
    private String provider;
    private Location location;
    private GPSHandler fineGPSHandler;
    private GPSHandler networkGPSHandler;
    LocationManager locationManager;
    private CurrentLocationListener currentUIListener;
    private boolean isGotFineLocation;
    private Timer networkLocationPauseTimer;
    private HandlerThread mTaskThread;
    private long lastFineGpsTimeStamp;
    private Timer timer;
    public CurrentLocationManager(Context context)
    {
        System.loadLibrary("OMS_HYBRID_ENGINE_JNIUTILS");
        locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
        Criteria fineCritea = new Criteria();
        fineCritea.setAltitudeRequired(true);
        fineCritea.setAccuracy(Criteria.ACCURACY_FINE);
        provider =  locationManager.getBestProvider(fineCritea, false);
        Location lastKnownFineLocation = locationManager.getLastKnownLocation(provider);
        
        if(LocationValidationUtil.isValidLocation(lastKnownFineLocation) && LocationValidationUtil.isFineLocation(lastKnownFineLocation))
        {
            location = lastKnownFineLocation;
        }
        else
        {
            Criteria coarseCriteria = new Criteria();
            coarseCriteria.setAccuracy(Criteria.ACCURACY_COARSE);
            provider = locationManager.getBestProvider(coarseCriteria, false);
            Location networkLocation = locationManager.getLastKnownLocation(provider);
            location = networkLocation;
        }
        
        networkGPSHandler = new GPSHandler();
        fineGPSHandler = new GPSHandler();
        networkGPSHandler.setHandlerListener(this);
        fineGPSHandler.setHandlerListener(this);
        mTaskThread = new HandlerThread("AsyncThread");
        mTaskThread.start();
        networkLocationPauseTimer = new Timer();
    }
    
    public Location getLocation()
    {
        location = new GpsEncryptRequest().convertGPSData(location);
        return location;
    }
    
    public String getProvider()
    {
        return this.provider;
    }
    
    public void setUpdateListener(CurrentLocationListener listener)
    {
        this.currentUIListener = listener;
    }
    
    public void startUpdateLocation()
    {
        isGotFineLocation = false;
        Logger.getLogger("locRecord").info("***************Request gps location too!");
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, LOCATION_NOTIFICATION_DURATION, 1,
                fineGPSHandler);

        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, LOCATION_NOTIFICATION_DURATION, 1,
                networkGPSHandler);
        Logger.getLogger("locRecord").info("***************Request network location too!");
        this.currentUIListener.updateCurrentLocation(FLAG_LOCATION_REQUIRING);
    }
    
    public void stopUpdateLocation()
    {
        this.networkLocationPauseTimer.cancel();
        if(fineGPSHandler != null)
        {
            locationManager.removeUpdates(fineGPSHandler);
        }
        if(networkGPSHandler != null)
        {
            locationManager.removeUpdates(networkGPSHandler);
        }
    }
    
    public interface CurrentLocationListener
    {
        public void updateCurrentLocation(int conditionflag);
    }

    @Override
    public synchronized void  handleGPSEvent(int handlePolicy, Location location, GPSHandler gpsHandler)
    {
        this.location = location;
        switch(handlePolicy)
        {
            case GPSHandler.POLICY_PROVIDER_DISABLED:
            {
                handleProviderDisable(gpsHandler);
                break;
            }
            case GPSHandler.POLICY_PROVIDER_ENABLED:
            {
                handleProviderEnable(gpsHandler);
                break;
            }
            case GPSHandler.POLICY_STATUS_CHANGED:
            {
                handleStatusChanged(gpsHandler);
                break;
            }
            case GPSHandler.POLICY_LOCATION_CHANGED:
            {
                handleLocationChanged(gpsHandler);
                break;
            }
        }
        
    }

    private void handleLocationChanged(GPSHandler gpsHandler)
    {
        if (gpsHandler.getProvider().equals(LocationManager.GPS_PROVIDER))
        {
            isGotFineLocation = true;
            if(this.timer != null)
            {
                timer.cancel();
            }
            this.timer = new Timer();
            NetworkLocationTimeTask netLocationTimeTask = new NetworkLocationTimeTask(this.locationManager, this.networkGPSHandler);
            timer.schedule(netLocationTimeTask, 15 * 1000);
            this.lastFineGpsTimeStamp = System.currentTimeMillis();
        }
        else
        {
            if(isGotFineLocation  && (System.currentTimeMillis() - lastFineGpsTimeStamp) <= 15 * 1000)
            {
                return;
            }
            else
            {
                isGotFineLocation = false;
            }
        }
        currentUIListener.updateCurrentLocation(FLAG_NEW_LOCATION_ARRIVAL);
      
    }

    private void handleStatusChanged(GPSHandler gpsHandler)
    {
        Logger.getLogger("locRecord").info("*************** handle Status Changed!");
        if(gpsHandler.getProvider().equals(LocationManager.GPS_PROVIDER))
        {
            isGotFineLocation = false;
            locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                    LOCATION_NOTIFICATION_DURATION * 30, 1, networkGPSHandler);
            this.provider = networkGPSHandler.getProvider();
        }
        currentUIListener.updateCurrentLocation(FLAG_LOCATION_REQUIRING);
    }

    private void handleProviderEnable(GPSHandler gpsHandler)
    {
        // TODO Auto-generated method stub
        
    }

    private void handleProviderDisable(GPSHandler gpsHandler)
    {
        if(gpsHandler.getProvider().equals(LocationManager.GPS_PROVIDER))
        {
            currentUIListener.updateCurrentLocation(FLAG_LOCATION_DEVICE_OFF);
        }
    }
}


class GPSHandler implements LocationListener
{
    public static final int POLICY_PROVIDER_DISABLED = 1;
    public static final int POLICY_PROVIDER_ENABLED = 2;
    public static final int POLICY_LOCATION_CHANGED = 3;
    public static final int POLICY_STATUS_CHANGED = 4;
    
    protected Location currentLocation;
    protected int status;
    protected String provider;
    private GPSHandlerListener handlerListener;
    @Override
    public void onLocationChanged(Location location)
    {
        this.currentLocation = location;
        this.provider = location.getProvider();
        if(handlerListener != null)
        {
            handlerListener.handleGPSEvent(POLICY_LOCATION_CHANGED, location, this);
        }
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras)
    {
        Logger.getLogger("locRecord").info("*************** Provider:" + provider + " status:" + status);
        this.currentLocation = null;
        this.status = status;
        this.provider = provider;
        if(handlerListener != null)
        {
            handlerListener.handleGPSEvent(POLICY_STATUS_CHANGED, null, this);
        }
    }

    @Override
    public void onProviderEnabled(String provider)
    {
        this.currentLocation = null;
        this.provider = provider;
        if(handlerListener != null)
        {
            handlerListener.handleGPSEvent(POLICY_PROVIDER_ENABLED, null, this);
        }
    }

    @Override
    public void onProviderDisabled(String provider)
    {
        this.currentLocation = null;
        this.provider = provider;
        if(handlerListener != null)
        {
            handlerListener.handleGPSEvent(POLICY_PROVIDER_DISABLED, null, this);
        }
    }
    
    
    public int getStatus()
    {
        return this.status;
    }
    
    public String getProvider()
    {
        return this.provider;
    }
    
    public void setHandlerListener(GPSHandlerListener handlerListener)
    {
        this.handlerListener = handlerListener;
    }
    
    public Location getCurrentLocation()
    {
        return this.currentLocation;
    }
    
    public interface GPSHandlerListener
    {
        public void handleGPSEvent(int handlePolicy, Location currentLocation, GPSHandler gpsHandler);
    }
    
}



class NetworkLocationTimeTask extends TimerTask
{
    LocationManager locMgr;
    GPSHandler gpsHandler;
    public NetworkLocationTimeTask(LocationManager locMgr, GPSHandler gpsHandler)
    {
       this.locMgr = locMgr;
       this.gpsHandler = gpsHandler;
    }

    @Override
    public void run()
    {
        Looper.prepare();
        Looper looper = Looper.myLooper();
        locMgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                1000 * 30, 1, gpsHandler, looper);
        Looper.loop();
    }
    
}